import fs from 'fs';
import path from 'path';
import dayjs from 'dayjs';
import iconv from 'iconv-lite';
import * as cheerio from 'cheerio';
import { message } from '../utils/Utils.mjs';
import DateUtils from '../utils/DateUtils.mjs';
import FsDriver from './FsDriver.mjs';

const fsDriver = new FsDriver();

/**
 * 采集数据控制器
 * 说明：
 * - 大乐透开奖时间：每周一、三、六 21:25 开奖
 * - 双色球开奖时间：每周二、四、日 21:15 开奖
 * - 周五休息
 * - 采集时间间隔 2 小时
 * @version 1.0.0
 */
class SpiderModel {
    logFile = '';
    constructor() {
        this.logFile = path.join(import.meta.dirname, '../data/log/spider-' + (new DateUtils()).format('Ymd') + '.log');
        fsDriver.mkdir(this.logFile, true);
    }
    async run(module = '', interval = 7200) {
        fsDriver.log(this.logFile, '采集开始');
        let msg = '';
        if (module == '') {
            let weekday = (new Date()).getDay();
            let weekdayName = ['天', '一', '二', '三', '四', '五', '六'][weekday];
            if (weekday == 5) {
                msg = '星期' + weekdayName + ' 不执行';
                fsDriver.log(this.logFile, msg);
                return message(null, msg);
            }
            let isDlt = weekday == 1 || weekday == 3 || weekday == 6;
            // let isSsq = weekday == 2 || weekday == 4 || weekday == 0;
            module = isDlt ? 'dlt' : 'ssq';
        }
        let taskDir = path.join(import.meta.dirname, '../data/task/');
        if (!fs.existsSync(taskDir)) {
            fs.mkdirSync(taskDir, { recursive: true });
        }
        let filePath = path.join(taskDir, 'spider.json');
        let data = fs.existsSync(filePath) ? JSON.parse(fs.readFileSync(filePath)) : {};
        if (data[module] && (dayjs(data[module]).add(interval, 'second').unix() > dayjs().unix())) {
            msg = `采集时间间隔 ${interval} 秒，下次采集时间为 ${dayjs(data[module]).add(interval, 'second').format('YYYY-MM-DD HH:mm:ss')}，请勿频繁采集。`;
            fsDriver.log(this.logFile, msg);
            return message(null, msg)
        }
        switch (module) {
            case 'dlt':
                await this.fetchDlt();
                break;
            case 'ssq':
                await this.fetchSsq();
                break;
        }
        data[module] = dayjs().format('YYYY-MM-DD HH:mm:ss');
        fs.writeFileSync(filePath, JSON.stringify(data));
        fsDriver.log(this.logFile, '采集结束');
        return message();

    }

    /**
     * 采集大乐透历史开奖数据
     * 大乐透开奖时间：每周一、三、六 21:25 开奖
     * 官网：https://www.lottery.gov.cn/dlt/index.html
     * 定时任务：30 21 * * * dltcj.php
     * @version 1.1.0
     */
    async fetchDlt() {
        let msg = '';
        const dataDir = path.join(import.meta.dirname, '../data/dlt/');
        if (!fs.existsSync(dataDir)) {
            fs.mkdirSync(dataDir, { recursive: true });
        }
        let cacheFile = dataDir + 'cache-' + dayjs().format('YYYYMMDD') + '.json';
        let fileName = dataDir + 'data-all.json';
        let data = fs.existsSync(fileName) ? JSON.parse(fs.readFileSync(fileName)) : [];
        let list = [];
        if (fs.existsSync(cacheFile)) {
            fsDriver.log(this.logFile, '【大乐透】获取本地缓存数据');
            list = JSON.parse(fs.readFileSync(cacheFile));
        } else {
            const url = 'https://webapi.sporttery.cn/gateway/lottery/getHistoryPageListV1.qry?gameNo=85&provinceId=0&pageSize=60&isVerify=1&pageNo=1&termLimits=60';
            try {
                const res = await (await fetch(url)).json();
                list = (res['data'] ? res.data : res).value.list.map(row => {
                    const { lotteryDrawNum, lotteryDrawResult, lotteryDrawTime } = row;
                    return { lotteryDrawNum, lotteryDrawResult, lotteryDrawTime };
                });
                fs.writeFileSync(cacheFile, JSON.stringify(list));
                fsDriver.log(this.logFile, '【大乐透】获取官方远程数据');
            } catch (error) {
                msg = '【大乐透】获取官方远程数据网络错误';
                console.log(message, error);
                fsDriver.log(this.logFile, msg);
            }
        }
        // 增量添加
        if (data.length > 0 && (list[list.length - 1].lotteryDrawNum < data[0].lotteryDrawNum)) {
            data.unshift(...list.filter(row => row.lotteryDrawNum > data[0].lotteryDrawNum));
            if (data.length > 200) {
                fs.writeFileSync(dataDir + 'data-backup-' + dayjs().format('YYYYMMDD') + '.json', JSON.stringify(data));
                data = data.slice(0, 100);
            }
        } else {
            data = list;
        }
        fs.writeFileSync(fileName, JSON.stringify(data));
        fsDriver.log(this.logFile, '【大乐透】采集完成');
    }

    /**
     * 采集双色球历史开奖数据
     * 双色球开奖时间：每周二、四、日 21：15 开奖
     * 官网：https://www.cwl.gov.cn/ygkj/kjgg/
     * 定时任务：30 21 * * * dltcj.php
     * @version 1.1.0
     */
    async fetchSsq() {
        let msg = '';
        const dataDir = path.join(import.meta.dirname, '../data/ssq/');
        if (!fs.existsSync(dataDir)) {
            fs.mkdirSync(dataDir, { recursive: true });
        }
        let cacheFile = dataDir + 'cache-' + dayjs().format('YYYYMMDD') + '.html';
        let fileName = dataDir + 'data-all.json';
        let data = fs.existsSync(fileName) ? JSON.parse(fs.readFileSync(fileName)) : [];
        let list = [], content = '';
        if (fs.existsSync(cacheFile)) {
            content = fs.readFileSync(cacheFile).toString();
            fsDriver.log(this.logFile, '【双色球】获取本地缓存数据');
        } else {
            const url = 'https://www.00038.cn/kjh/ssq/history.htm';
            try {
                content = await (await fetch(url)).text();
                if (content.includes('GB2312')) {
                    content = iconv.decode(content, 'GB2312');
                }
                fs.writeFileSync(cacheFile, content);
                msg = '【双色球】获取官方远程数据';
                console.log(message, content);
                fsDriver.log(this.logFile, msg);
            } catch (error) {
                msg = '【双色球】获取官方远程数据网络错误';
                console.log(message, error);
                fsDriver.log(this.logFile, msg);
            }
        }
        const $ = cheerio.load(content);
        let tds = [];
        $('table.kjhTable tr').each((i, $tr) => {
            if (i < 2) {
                return;
            }
            tds = $($tr).find('td');
            list.push({
                "lotteryDrawNum": $(tds[0]).text(),
                "lotteryDrawResult": $(tds[2]).text().replace(/\\n|\+/g, ' ').replace(/\s+/g, ' ').trim(),
                "lotteryDrawTime": $(tds[1]).text()
            })
        })
        // 增量添加
        if (data.length > 0 && (list[list.length - 1].lotteryDrawNum < data[0].lotteryDrawNum)) {
            data.unshift(...list.filter(row => row.lotteryDrawNum > data[0].lotteryDrawNum));
        } else {
            data = list;
        }
        fs.writeFileSync(fileName, JSON.stringify(data));
        fsDriver.log(this.logFile, '【双色球】采集完成');
    }
}


export default SpiderModel;